/**
 * Exactly the same as the default toggle() method, with the exception that
 * three states may be toggled between. Three functions should be passed into
 * this method.
 */
jQuery.fn.toggle3way = function(fn) {
    // Save reference to arguments for access in closure
    var args = arguments, i = 2;

    // link all the functions, so any of them can unbind this click handler
    while (i < args.length)
        jQuery.event.proxy(fn, args[i++]);

    return this.click(jQuery.event.proxy(fn, function(event) {
        // Figure out which function to execute
        this.lastToggle = (this.lastToggle || 0) % i;

        // Make sure that clicks stop
        event.preventDefault();

        // and execute the function
        return args[ this.lastToggle++ ].apply(this, arguments) || false;
    }));
};


var TASK_DISPLAY_LEVEL = [
    ""
    , String.fromCharCode(19968)  // 1
    , String.fromCharCode(20108)  // 2
    , String.fromCharCode(19977)  // 3
];


$(document).ready(function() {
    // hide the fully-qualified path of the class
    
    $('.task-name').each(function() {
        var taskClass = $(this).text();
        $(this).text(taskClass.replace(/.*\./, ""));
    });
    
    // hide the passing nested results initially. Results with non-passing
    // statuses are not hidden.
    
    $('.task').each(function() {
        showByStatus(this, 1, 0);
        setDisplayLevel(this, 2);
    });
    
    // add toggle for nested tasks
    
    $('.task-header').toggle3way(
        function() {
            // show all
            showByStatus($(this).parents('.task')[0], -1);
            setDisplayLevel(this, 3);
        }
        , function() {
            // hide all
            showByStatus($(this).parents('.task')[0], 100);
            setDisplayLevel(this, 1);
        }
        , function() {
            // show only flagged and higher priority
            showByStatus($(this).parents('.task')[0], 1);
            setDisplayLevel(this, 2);
        }
    );
    
    // add expander
    
    $('.task').hover(
        function() {
            if ($(this).parents('.task').length > 0) {
                return
            }
            $(this).find('.task-info > td').each(function() {
                $(this).animate({
                    fontSize: '12px',
                    padding: '2px'
                })
            });
        }
        , function() {
            if ($(this).parents('.task').length > 0) {
                return
            }
            $(this).find('.task-info > td').each(function() {
                $(this).animate({
                    fontSize: '0%',
                    padding: '0'
                })
            });
        }
    );
    
    // style the task result header
    
    $('.task-result').each(function() {
        var header = $(this).find('.task-header');
        
        switch (getStatus(this)) {
            case 1:
                header.addClass('flagged');
                break;
            case 2:
                header.addClass('failed');
                break;
            case 3:
                header.addClass('doomed');
                break;
            default:
                header.addClass('passed');
                break;
        }
    });
});


/**
 * Returns a numeric status for a given task result node.
 *
 * @param taskResult  the task-result node
 */
function getStatus(taskResult) {
    var taskStatus = $(taskResult).find('.task-status')[0];
    return parseInt(taskStatus.firstChild.nodeValue);
}

/**
 * Hides tasks recursively based on if their status values are less than or
 * equal to a status threshold. Shows them otherwise.
 *
 * @param task
 * @param statusThreshold  the minimum status to hide
 * @param showSpeed        the speed to use when showing or hiding. The default
 *                         is 'slow'. A number indicating ms may be provided.
 */
function showByStatus(task, statusThreshold, showSpeed) {
    if (showSpeed == null) {
        showSpeed = 'slow';
    }
    $(task).find('.task').each(function() {
        if (getStatus($(this).find('.task-result')[0]) >= statusThreshold) {
            $(this).show(showSpeed);
        }
        else {
            $(this).hide(showSpeed);
        }
        showByStatus(this, statusThreshold);
    });
}

function setDisplayLevel(task, level) {
    var displayLevel = $(task).find('.task-display-level')[0];
    $(displayLevel).text(TASK_DISPLAY_LEVEL[level]);
}



